using System;
using System.Collections.Generic;
using System.Text;

namespace EuropeEngulfed.NET
{
    abstract class Block : PlayingPiece
    {
        public enum BlockType
        {
            militia,
            infantry,
            cavalry,
            armor,
            airborne,
            eliteArmor,
            eliteInfantry,
        }
        private uint maxStrength;
        private uint currentStrength;

        public uint MaxStrength
        {
            get
            {
                return maxStrength;
            }
        }

        public uint CurrentStrength
        {
            get
            {
                return currentStrength;
            }

            set
            {
                if (value <= maxStrength)
                    currentStrength = value;
                else
                    throw new InvalidOperationException();
            }
        }

        public abstract BlockType getBlockType();

        public bool IsArmorClass()
        {
            return getBlockType() == BlockType.armor || getBlockType() == BlockType.eliteArmor;
        }

        public bool IsInfantryClass()
        {
            return getBlockType() != BlockType.armor && getBlockType() != BlockType.eliteArmor;
        }

        public bool IsElite()
        {
            return getBlockType() == BlockType.eliteArmor || getBlockType() == BlockType.eliteInfantry;
        }

        public Block(MapInfo.CountryID countryOwner,uint maxStrength) : base(countryOwner)
        {
            this.countryOwner = countryOwner;
            this.maxStrength = maxStrength;
            this.currentStrength = maxStrength;
            OutOfSupplyState = OOSState.InSupply;
        }

        public new abstract Block Copy();

        public System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("Block");
            System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("Country");
            countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), this.CountryOwner);
            nodeToReturn.Attributes.Append(countryAttr);
            System.Xml.XmlAttribute typeAttr = xml.CreateAttribute("Type");
            typeAttr.Value = Enum.GetName(typeof(Block.BlockType), this.getBlockType());
            nodeToReturn.Attributes.Append(typeAttr);
            System.Xml.XmlAttribute maxStrengthAttr = xml.CreateAttribute("MaxStrength");
            maxStrengthAttr.Value = this.maxStrength.ToString();
            nodeToReturn.Attributes.Append(maxStrengthAttr);
            System.Xml.XmlNode OOSNode = xml.CreateElement("OOS");
            OOSNode.InnerText = this.OutOfSupply.ToString();
            nodeToReturn.AppendChild(OOSNode);
            System.Xml.XmlNode currentStrengthNode = xml.CreateElement("CurrentStrength");
            currentStrengthNode.InnerText = this.currentStrength.ToString();
            nodeToReturn.AppendChild(currentStrengthNode);

            return nodeToReturn;
        }

        public new static Block Deserialise(System.Xml.XmlNode node)
        {
            Block blockToReturn = null;
            if(node.Name == "Block")
            {
                switch((Block.BlockType)Enum.Parse(typeof(Block.BlockType),node.Attributes["Type"].Value))
                {
                    case BlockType.airborne:
                        blockToReturn = new AirborneBlock((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["Country"].Value), (uint)Int32.Parse(node.Attributes["MaxStrength"].Value));
                        break;
                    case BlockType.armor:
                        blockToReturn = new ArmorBlock((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["Country"].Value), (uint)Int32.Parse(node.Attributes["MaxStrength"].Value));
                        break;
                    case BlockType.cavalry:
                        blockToReturn = new CavalryBlock((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["Country"].Value), (uint)Int32.Parse(node.Attributes["MaxStrength"].Value));
                        break;
                    case BlockType.eliteArmor:
                        blockToReturn = new EliteArmorBlock((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["Country"].Value), (uint)Int32.Parse(node.Attributes["MaxStrength"].Value));
                        break;
                    case BlockType.eliteInfantry:
                        blockToReturn = new EliteInfantryBlock((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["Country"].Value), (uint)Int32.Parse(node.Attributes["MaxStrength"].Value));
                        break;
                    case BlockType.infantry:
                        blockToReturn = new InfantryBlock((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["Country"].Value), (uint)Int32.Parse(node.Attributes["MaxStrength"].Value));
                        break;
                    case BlockType.militia:
                        blockToReturn = new MilitiaBlock((MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["Country"].Value), (uint)Int32.Parse(node.Attributes["MaxStrength"].Value));
                        break;
                }

                foreach(System.Xml.XmlNode blockNode in node)
                {
                    switch (blockNode.Name)
                    {
                        case "OOS":
                            try
                            {
                                blockToReturn.OutOfSupplyState = (OOSState)Enum.Parse(typeof(OOSState), blockNode.InnerText);
                            }
                            catch //TO allow me to load old files that had just true/false for the supply state. /TODO remove
                            {
                                bool bOOS = bool.Parse(blockNode.InnerText);
                                if (bOOS)
                                    blockToReturn.OutOfSupplyState = OOSState.OOS;
                                else
                                    blockToReturn.OutOfSupplyState = OOSState.InSupply;
                            }

                            break;
                        case "CurrentStrength":
                            blockToReturn.CurrentStrength = (uint)Int32.Parse(blockNode.InnerText);
                            break;
                    }
                }
            }

            return blockToReturn;
        }

        public bool Equals(Block blockToCompare)
        {
            if (this.getBlockType() != blockToCompare.getBlockType())
                return false;
            if (this.countryOwner != blockToCompare.countryOwner)
                return false;
            if (this.currentStrength != blockToCompare.currentStrength)
                return false;
            if (this.maxStrength != blockToCompare.maxStrength)
                return false;
            if (this.OutOfSupply != blockToCompare.OutOfSupply)
                return false;
            return true;
        }

        public override string GetHiddenStringDescription()
        {
            return (IsElite() ? "Elite " : "") + MapInfo.GetCountryAdjective(this.countryOwner) + " block";
        }
    }
}
